#!/usr/bin/python
# -*- coding: utf-8 -*-
"""

================================================================================

    mingus - Music theory Python package, string tuning module
    Copyright (C) 2009, Bart Spaans

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

================================================================================

        The tunings module provides dozens of standard tunings, a StringTuning
        class and some functions to help you search through them.

================================================================================"""

from mingus.containers.Note import Note
from mingus.containers.NoteContainer import NoteContainer
from mingus.core.mt_exceptions import RangeError
import mingus.core.notes as notes


class StringTuning:

    """StringTuning can be used to store and work with tunings and fingerings."""

    def __init__(
        self,
        instrument,
        description,
        tuning,
        ):
        """`instrument` and `description` should be strings. tuning should be a \
list of strings or a list of lists of strings that denote courses. See \
tunings.add_tuning for examples."""

        self.instrument = instrument
        self.tuning = []

                # convert to Note

        for x in tuning:
            if type(x) == list:
                self.tuning.append([Note(n) for n in x])
            else:
                self.tuning.append(Note(x))
        self.description = description

    def count_strings(self):
        """Returns the number of strings."""

        return len(self.tuning)

    def count_courses(self):
        """Returns the average number of courses per string,"""

        c = 0
        for x in self.tuning:
            if type(x) == list:
                c += len(x)
            else:
                c += 1
        return float(c) / len(self.tuning)

    def find_frets(self, note, maxfret=24):
        """Returns a list with for each string the fret on which the note is played \
or None if it can't be played on that particular string. `maxfret` is \
the highest fret that can be played. `note` should either be a string or \
a Note object.
{{{
>>> t = tunings.StringTuning(\"test\", \"test\", [\"A-3\", \"E-4\"])
>>> t.find_frets(Note(\"C-4\")
[3, None]
>>> t.find_frets(Note(\"A-4\")
[12, 5]
}}}"""

        result = []
        if type(note) == str:
            note = Note(note)
        for x in self.tuning:
            if type(x) == list:
                base = x[0]
            else:
                base = x
            diff = base.measure(note)
            if 0 <= diff <= maxfret:
                result.append(diff)
            else:
                result.append(None)
        return result

    def find_fingering(
        self,
        notes,
        max_distance=4,
        not_strings=[],
        ):
        """Returns a list [(string, fret)] of possible fingerings for `notes`. \
`notes` should be a list of strings or Notes or a !NoteContainer. \
`max_distance` denotes the maximum distance between frets. `not_strings` \
can be used to disclude certain strings and is used internally to \
recurse.
{{{
>>> t = tunings.StringTuning(\"test\", \"test\", [\"A-3\", \"E-4\", \"A-5\"])
>>> t.find_fingering(['E-4', 'B-4'])
[[(0, 7), (1, 7)], [(1, 0), (0, 14)]]
}}}"""

        if notes is None:
            return []
        if len(notes) == 0:
            return []
        first = notes[0]
        notes = notes[1:]
        frets = self.find_frets(first)
        result = []
        for (string, fret) in enumerate(frets):
            if fret is not None and string not in not_strings:
                if len(notes) > 0:

                                        # recursively find fingerings for
                                        # remaining notes

                    r = self.find_fingering(notes, max_distance, not_strings
                             + [string])
                    if r != []:
                        for f in r:
                            result.append([(string, fret)] + f)
                else:
                    result.append([(string, fret)])

                # filter impossible fingerings and sort

        res = []
        for r in result:
            (min, max) = (1000, -1)
            frets = 0
            for (string, fret) in r:
                if fret > max:
                    max = fret
                if fret < min and fret != 0:
                    min = fret
                frets += fret
            if 0 <= max - min < max_distance or min == 1000 or max == -1:
                res.append((frets, r))
        return [r for (_, r) in sorted(res)]

    def find_chord_fingering(
        self,
        notes,
        max_distance=4,
        maxfret=18,
        return_best_as_NoteContainer=False,
        ):
        """Returns a list of fret lists that are considered possible fingerings. \
This function only looks at and matches on the note _names_ so it does \
more than `find_fingering`. For example: {{{
>>> t = tunings.get_tuning(\"guitar\", \"standard\", 6, 1)
>>> t.find_chord_fingering(NoteContainer().from_chord(\"Am\"))
[[0, 0, 2, 2, 1, 0],
 [0, 3, 2, 2, 1, 0], ......]
}}}"""

        def follow(
            string,
            next,
            name,
            prev=-1,
            ):
            """Follow the fret `next` on `string`. And build result on the way."""

            if string >= len(self.tuning) - 1:
                return [[(next, name)]]
            result = []
            cur = res[string][next]
            if cur != []:
                for y in cur[1]:
                    for sub in follow(string + 1, y[0], y[1]):
                        if prev < 0:
                            result.append([(next, name)] + sub)
                        else:
                            if sub[0][0] == 0 or abs(sub[0][0] - prev)\
                                 < max_distance:
                                result.append([(next, name)] + sub)
            for s in follow(string + 1, maxfret + 1, None, next):
                result.append([(next, name)] + s)
            return [[(next, name)]] if result == [] else result

        def make_lookup_table():
            """Prepare the lookup table. table[string][fret] = (name, dest_frets)"""

            res = [[[] for x in xrange(maxfret + 2)] for x in
                   xrange(len(self.tuning) - 1)]
            for x in xrange(0, len(self.tuning) - 1):
                addedNone = -1
                next = fretdict[x + 1]
                for (fret, name) in fretdict[x]:
                    for (f2, n2) in next:
                        if n2 != name and (f2 == 0 or abs(fret - f2)
                                 < max_distance):
                            if res[x][fret] != []:
                                res[x][fret][1].append((f2, n2))
                            else:
                                res[x][fret] = (name, [(f2, n2)])
                        if addedNone < x:
                            if res[x][maxfret + 1] != []:
                                res[x][maxfret + 1][1].append((f2, n2))
                            else:
                                res[x][maxfret + 1] = (None, [(f2, n2)])
                    addedNone = x
            return res

                # Convert to NoteContainer if necessary

        n = notes
        if notes != [] and type(notes) == list and type(notes[0]) == str:
            n = NoteContainer(notes)

                # Check number of note names.

        notenames = [x.name for x in n]
        if len(notenames) == 0 or len(notenames) > len(self.tuning):
            return []

                # Make string-fret dictionary

        fretdict = []
        for x in xrange(0, len(self.tuning)):
            fretdict.append(self.find_note_names(notes, x, maxfret))

                # Build table

        res = make_lookup_table()

                # Build result using table

        result = []

                # For each fret on the first string

        for (i, y) in enumerate(res[0]):
            if y != []:
                (yname, next) = (y[0], y[1])

                                # For each destination fret in y

                for (fret, name) in next:

                                        # For each followed result

                    for s in follow(1, fret, name):
                        subresult = [(i, yname)] + s

                                                # Get boundaries

                        (mi, ma, names) = (1000, -1000, [])
                        for (f, n) in subresult:
                            if n is not None:
                                if f != 0 and f <= mi:
                                    mi = f
                                if f != 0 and f >= ma:
                                    ma = f
                                names.append(n)

                                                # Enforce boundaries

                        if abs(ma - mi) < max_distance:

                                                        # Check if all note
                                                        # names are present

                            covered = True
                            for n in notenames:
                                if n not in names:
                                    covered = False

                                                        # Add to result

                            if covered and names != []:
                                result.append([y[0] if y[1]
                                         is not None else y[1] for y in
                                        subresult])

                # Return semi-sorted list

        s = sorted(result, key=lambda x: sum([t if t is not None else 1000
                   for (i, t) in enumerate(x)]))
        if not return_best_as_NoteContainer:
            return s
        else:
            rnotes = self.frets_to_NoteContainer(s[0])
            for (i, x) in enumerate(rnotes):
                if x.string < len(self.tuning) - 1:
                    if res[x.string][x.fret] != []:
                        rnotes[i].name = res[x.string][x.fret][0]
            return rnotes

    def frets_to_NoteContainer(self, fingering):
        """Converts a list such as returned by find_fret to a NoteContainer."""

        res = []
        for (string, fret) in enumerate(fingering):
            if fret is not None:
                res.append(self.get_Note(string, fret))
        return NoteContainer(res)

    def find_note_names(
        self,
        notelist,
        string=0,
        maxfret=24,
        ):
        """Returns a list [(fret, notename)] in ascending order.
Notelist should be a list of Notes, note-strings or a NoteContainer.
{{{
>>> t = tunings.StringTuning(\"test\", \"test\", ['A-3', 'A-4'])
>>> t.find_note_names([\"A\", \"C\", \"E\"], 0, 12)
[(0, 'E'), (5, 'A'), (8, 'C'), (12, 'E')]
}}}"""

        n = notelist
        if notelist != [] and type(notelist[0]) == str:
            n = NoteContainer(notelist)
        result = []
        names = [x.name for x in n]
        int_notes = [notes.note_to_int(x) for x in names]

                # Base of the string

        s = int(self.tuning[string]) % 12
        for x in xrange(0, maxfret + 1):
            if (s + x) % 12 in int_notes:
                result.append((x, names[int_notes.index((s + x) % 12)]))
        return result

    def get_Note(
        self,
        string=0,
        fret=0,
        maxfret=24,
        ):
        """Returns the Note on `string`, `fret`. Throws a RangeError if either the \
fret or string is unplayable.
{{{
>>> t = tunings.StringTuning(\"test\", \"test\", ['A-3', 'A-4'])
>>> t,get_Note(0, 0)
'A-3'
>>> t.get_Note(0, 1)
'A#-3'
>>> t.get_Note(1, 0)
'A-4'
}}}"""

        if 0 <= string < self.count_strings():
            if 0 <= fret <= maxfret:
                s = self.tuning[string]
                if type(s) == list:
                    s = s[0]
                n = Note(int(s) + fret)
                n.string = string
                n.fret = fret
                return n
            else:
                raise RangeError, "Fret '%d' on string '%d' is out of range"\
                     % (string, fret)
        else:
            raise RangeError, "String '%d' out of range" % string


# The index

_known = {}


def add_tuning(instrument, description, tuning):
    """Add a new tuning to the index. `instrument` and `description` should be \
strings; `tuning` should be a list of strings or a list of lists to denote \
courses. For example:
{{{
>>> tuning.add_tuning(\"Guitar\", \"standard\", ['E-2', 'A-2', 'D-3', 'G-3', \
'B-3', 'E-4'])
>>> tuning.add_tuning(\"Guitar\", \"twelve string\", [['E-2', 'E-3'], ['A-2', \
'A-3'], ...etc.
}}}"""

    t = StringTuning(instrument, description, tuning)
    if _known.has_key(str.upper(instrument)):
        _known[str.upper(instrument)][1][str.upper(description)] = t
    else:
        _known[str.upper(instrument)] = (instrument,
                {str.upper(description): t})


def get_tuning(
    instrument,
    description,
    nr_of_strings=None,
    nr_of_courses=None,
    ):
    """Get the first tuning that satisfies the constraints. The `instrument` and \
`description` arguments are treated like case-insensitive prefixes. So \
search for 'bass' is the same is 'Bass Guitar'.
{{{
>>> tunings.get_tuning(\"guitar\", \"standard\")
<tunings.StringTuning instance at 0x139ac20>
}}}"""

    searchi = str.upper(instrument)
    searchd = str.upper(description)
    keys = _known.keys()
    for x in keys:
        if searchi not in keys and x.find(searchi) == 0 or searchi in keys and x\
             == searchi:
            for (desc, tun) in _known[x][1].iteritems():
                if desc.find(searchd) == 0:
                    if nr_of_strings is None and nr_of_courses is None:
                        return tun
                    elif nr_of_strings is not None and nr_of_courses is None:
                        if tun.count_strings() == nr_of_strings:
                            return tun
                    elif nr_of_strings is None and nr_of_courses is not None:
                        if tun.count_courses() == nr_of_courses:
                            return tun
                    else:
                        if tun.count_courses() == nr_of_courses\
                             and tun.count_strings() == nr_of_strings:
                            return tun


def get_tunings(instrument=None, nr_of_strings=None, nr_of_courses=None):
    """Allows you to search tunings on instrument, strings, courses or a \
combination. The instrument is actually treated like a case-insensitive \
prefix. So asking for 'bass' yields the same tunings as 'Bass Guitar'; the \
string 'ba' yields all the instruments starting with 'ba'.
{{{
>>> tunings.get_tunings(nr_of_string = 4)
>>> tunings.get_tunings(\"bass\")
}}}"""

    search = ''
    if instrument is not None:
        search = str.upper(instrument)
    result = []
    keys = _known.keys()
    inkeys = search in keys
    for x in keys:
        if instrument is None or not inkeys and x.find(search) == 0 or inkeys\
             and search == x:
            if nr_of_strings is None and nr_of_courses is None:
                result += _known[x][1].values()
            elif nr_of_strings is not None and nr_of_courses is None:
                result += [y for y in _known[x][1].itervalues()
                           if y.count_strings() == nr_of_strings]
            elif nr_of_strings is None and nr_of_courses is not None:
                result += [y for y in _known[x][1].itervalues()
                           if y.count_courses() == nr_of_courses]
            else:
                result += [y for y in _known[x][1].itervalues()
                           if y.count_strings() == nr_of_strings
                            and y.count_courses() == nr_of_courses]
    return result


def get_instruments():
    """Returns a sorted list of instruments that have string tunings defined for \
them."""

    return sorted([_known[upname][0] for upname in _known])


add_tuning('Baglamas (Greek)', 'Modal D standard tuning', [['D-4', 'D-5'],
           ['A-4', 'A-4'], ['D-5', 'D-5']])
add_tuning('Bajo quinto', 'Standard tuning.', [['A-2', 'A-1'], ['D-3', 'D-2'],
           ['G-2', 'G-2'], ['C-3', 'C-3'], ['F-3', 'F-3']])
add_tuning('Bajo Sexto', 'Standard tuning', [
    ['E-2', 'E-1'],
    ['A-2', 'A-1'],
    ['D-3', 'D-2'],
    ['G-2', 'G-2'],
    ['C-3', 'C-3'],
    ['F-3', 'F-3'],
    ])
add_tuning('Bandola Oriental', 'Standard tuning.', [['G-3', 'G-3'], ['D-4',
           'D-4'], ['A-4', 'A-4'], ['E-5', 'E-5']])
add_tuning('Banjo (bass)',
           'A cello banjo is sometimes called a "bass banjo",but there are true bass banjos as well'
           , ['E-1', 'A-1', 'D-2', 'G-2'])
add_tuning('Banjo (cello)', 'Standard tuning. Same as cello and mandocello',
           ['C-2', 'G-2', 'D-3', 'A-3'])
add_tuning('Banjo (tenor)', 'Standard tenor jazz tuning', ['C-3', 'G-3', 'D-4',
           'A-4'])
add_tuning('Banjo (tenor)', 'Irish tenor tuning', ['G-2', 'D-3', 'A-3', 'E-4'])
add_tuning('Banjo (5-string)', 'Open G tuning', ['G-4', 'D-3', 'G-3', 'B-3',
           'D-4'])
add_tuning('Baritone guitar', 'Standard 5th lower tuning', [
    'A-1',
    'D-2',
    'G-2',
    'C-3',
    'E-3',
    'A-3',
    ])
add_tuning('Baritone guitar', 'Octave lower tuning', [
    'E-1',
    'A-1',
    'D-2',
    'G-2',
    'B-2',
    'E-3',
    ])
add_tuning('Bass guitar', 'Standard 4-string tuning', ['E-1', 'A-1', 'D-2',
           'G-2'])
add_tuning('Bass guitar', 'Standard 5-string tuning', ['B-0', 'E-1', 'A-1',
           'D-2', 'G-2'])
add_tuning('Bass guitar', 'Alternate 5-string tuning', ['E-1', 'A-1', 'D-2',
           'G-2', 'C-3'])
add_tuning('Bass guitar', 'Standard 6-string tuning', [
    'B-0',
    'E-1',
    'A-1',
    'D-2',
    'G-2',
    'C-3',
    ])
add_tuning('Cello', 'Standard tuning', ['C-2', 'G-2', 'D-3', 'A-3'])
add_tuning('Cello', '"5th Suite" tuning', ['C-2', 'G-2', 'D-3', 'G-3'])
add_tuning('Cello banjo', 'Standard tuning', ['C-2', 'G-2', 'D-3', 'A-3'])
add_tuning('Charango', 'Standard C6 tuning. 3rd course is an octave pair.',
           [['G-4', 'G-4'], ['C-4', 'C-4'], ['E-5', 'E-4'], ['A-4', 'A-4'],
           ['E-5', 'E-5']])
add_tuning('Charangon', 'F6 tuning', [['C-4', 'C-4'], ['F-4', 'F-4'], ['A-5',
           'A-4'], ['D-5', 'D-5'], ['A-5', 'A-5']])
add_tuning('Charangon', 'G6 tuning', [['D-4', 'D-4'], ['G-4', 'G-4'], ['B-5',
           'B-4'], ['E-5', 'E-5'], ['B-5', 'B-5']])
add_tuning('Cuatro', 'Standard tuning', [['B-3', 'B-2'], ['E-4', 'E-3'], ['A-3'
           , 'A-3'], ['D-4', 'D-4'], ['G-4', 'G-4']])
add_tuning('Double bass', 'Orchestral tuning', ['E-1', 'A-1', 'D-2', 'G-2'])
add_tuning('Dulcimer',
           'Ionian Tuning (The traditional dulcimer is fretted diatonically whole, whole, half, whole, whole, half, whole. )'
           , ['A-3', 'A-3', 'D-3'])
add_tuning('Dulcimer', 'Mixolydian Tuning', ['D-4', 'A-3', 'D-3'])
add_tuning('Dulcimer', 'Dorian Tuning', ['G-3', 'A-3', 'D-3'])
add_tuning('Dulcimer', 'Aeolian Tuning', ['C-4', 'A-3', 'D-3'])
add_tuning('Fiddle', 'Standard tuning', ['G-3', 'D-4', 'A-4', 'E-5'])
add_tuning('Fiddle', 'Cajun tuning', ['F-3', 'C-4', 'G-4', 'F-5'])
add_tuning('Fiddle', 'Open G tuning', ['G-3', 'D-4', 'G-4', 'B-4'])
add_tuning('Fiddle', 'Sawmill tuning', ['G-3', 'D-4', 'G-4', 'D-5'])
add_tuning('Fiddle', '"Gee-dad"', ['G-3', 'D-4', 'A-4', 'D-5'])
add_tuning('Fiddle', 'Open D tuning', ['D-3', 'D-4', 'A-4', 'D-5'])
add_tuning('Fiddle', 'Old-timey D tuning', ['A-3', 'D-4', 'A-4', 'E-5'])
add_tuning('Fiddle', 'Cross Tuning, High bass, high counter', ['A-3', 'E-4',
           'A-4', 'E-5'])
add_tuning('Gadulka', '3 playing strings, with up to 10 sympathetic strings.',
           ['A-3', 'E-3', 'A-4'])
add_tuning('Greek Bouzouki', 'Standard F6 tuning', [['C-3', 'C-4'], ['F-3',
           'F-4'], ['A-3', 'A-3'], ['D-4', 'D-4']])
add_tuning('Greek Bouzouki', 'Standard F6 tuning', [['D-3', 'D-4'], ['A-3',
           'A-3'], ['D-4', 'D-4']])
add_tuning('Guitar', 'Standard tuning', [
    'E-2',
    'A-2',
    'D-3',
    'G-3',
    'B-3',
    'E-4',
    ])
add_tuning('Guitar', '*DADGAD* Dsus4 tuning', [
    'D-2',
    'A-2',
    'D-3',
    'G-3',
    'A-3',
    'D-4',
    ])
add_tuning('Guitar', 'Double drop D tuning', [
    'D-2',
    'A-2',
    'D-3',
    'G-3',
    'B-3',
    'D-4',
    ])
add_tuning('Guitar', 'Drop D tuning', [
    'D-2',
    'A-2',
    'D-3',
    'G-3',
    'B-3',
    'E-4',
    ])
add_tuning('Guitar', 'Open C major tuning', [
    'C-2',
    'G-2',
    'C-3',
    'G-3',
    'C-3',
    'E-4',
    ])
add_tuning('Guitar', 'Open E minor tuning', [
    'E-2',
    'B-2',
    'E-3',
    'G-3',
    'B-3',
    'E-4',
    ])
add_tuning('Guitar', 'Open G major tuning', [
    'D-2',
    'G-2',
    'D-3',
    'G-3',
    'B-3',
    'D-4',
    ])
add_tuning('Guitar',
           'Standard tuning. Some players tune the second course G string to unison to minimize breakage.'
           , [
    ['E-2', 'E-3'],
    ['A-2', 'A-3'],
    ['D-3', 'D-4'],
    ['G-3', 'G-4'],
    ['B-3', 'B-3'],
    ['E-4', 'E-4'],
    ])
add_tuning('Guitar Banjo', 'Standard guitar tuning', [
    'E-2',
    'A-2',
    'D-3',
    'G-3',
    'B-3',
    'E-4',
    ])
add_tuning("Guitarrón", 'Standard tuning', [
    'A-1',
    'D-2',
    'G-2',
    'C-3',
    'E-3',
    'A-2',
    ])
add_tuning('Huapanguera', '', ['G-2', ['D-3', 'D-4'], ['G-3', 'G-3'], ['B-3',
           'B-3'], 'E-3'])
add_tuning('Irish bouzouki', 'Irish tuning (octaves)', [['G-3', 'G-2'], ['D-4',
           'D-3'], ['A-3', 'A-3'], ['D-4', 'D-4']])
add_tuning('Irish bouzouki', 'Irish tuning (unison pairs)', [['G-2', 'G-2'],
           ['D-3', 'D-3'], ['A-3', 'A-3'], ['D-4', 'D-4']])
add_tuning('Irish bouzouki', '"Mandolin" tuning (octaves)', [['G-3', 'G-2'],
           ['D-4', 'D-3'], ['A-3', 'A-3'], ['E-4', 'E-4']])
add_tuning('Irish bouzouki', '"Mandolin" tuning (unison pairs)', [['G-2', 'G-2'
           ], ['D-3', 'D-3'], ['A-3', 'A-3'], ['E-4', 'E-4']])
add_tuning('Irish bouzouki', 'Modal D tuning (octaves)', [['A-3', 'A-2'], ['D-4'
           , 'D-3'], ['A-3', 'A-3'], ['D-4', 'D-4']])
add_tuning('Irish bouzouki', 'Modal D tuning (unison pairs)', [['A-2', 'A-2'],
           ['D-3', 'D-3'], ['A-3', 'A-3'], ['D-4', 'D-4']])
add_tuning('Mandobass', 'Standard tuning', ['E-1', 'A-1', 'D-2', 'G-2'])
add_tuning('Mandola',
           'Standard tuning. Pitched a 5th below mandolin tuning.  Known in Europe as the tenor mandola.'
           , [['C-3', 'C-3'], ['G-3', 'G-3'], ['D-4', 'D-4'], ['A-4', 'A-4']])
add_tuning('Mandocello', 'Standard tuning. Pitched an octave below the mandola.'
           , [['C-2', 'C-2'], ['G-2', 'G-2'], ['D-3', 'D-3'], ['A-3', 'A-3']])
add_tuning('Mandolin', 'Standard tuning', [['G-3', 'G-3'], ['D-4', 'D-4'],
           ['A-4', 'A-4'], ['E-5', 'E-5']])
add_tuning('Mandolin (piccolo)', 'Standard tuning', [['C-4', 'C-4'], ['G-4',
           'G-4'], ['D-5', 'D-5'], ['A-5', 'A-5']])
add_tuning('Mandolin (Octave)',
           'Standard tuning. Known in Europe as the octave mandola.  Pitched an octave below the mandolin.'
           , [['G-2', 'G-2'], ['D-3', 'D-3'], ['A-3', 'A-3'], ['E-4', 'E-4']])
add_tuning('Mejorana', 'Standard tuning', ['D-4', 'A-4', 'A-3', 'B-3', 'E-4'])
add_tuning('Mejorana', 'Alternative tuning', ['D-4', 'G-4', 'G-3', 'B-3', 'E-3'
           ])
add_tuning('Octave Guitar', 'see *Soprano guitar*', [
    'E-3',
    'A-4',
    'D-4',
    'G-4',
    'B-4',
    'E-5',
    ])
add_tuning('Requinto', 'Standard tuning', [
    'A-2',
    'D-3',
    'G-3',
    'C-4',
    'E-4',
    'A-4',
    ])
add_tuning('Ronroco', 'Standard C6 tuning (tuned an octave below the charango).'
           , [['G-3', 'G-3'], ['C-3', 'C-3'], ['E-4', 'E-3'], ['A-3', 'A-3'],
           ['E-4', 'E-4']])
add_tuning('Soprano guitar', 'Standard tuning', [
    'E-3',
    'A-4',
    'D-4',
    'G-4',
    'B-4',
    'E-5',
    ])
add_tuning('Taro patch',
           'Standard C6 tuning. The taro patch is a double-string ukulele.',
           [['G-3', 'G-4'], ['C-3', 'C-4'], ['E-4', 'E-4'], ['A-4', 'A-4']])
add_tuning('Tenor guitar', 'Standard tuning.', ['C-3', 'G-3', 'D-4', 'A-4'])
add_tuning('Tiple', 'Standard Colombian G6 tuning.', [['D-4', 'D-3', 'D-4'],
           ['G-4', 'G-3', 'G-4'], ['B-3', 'B-3', 'B-3'], ['E-4', 'E-4', 'E-4']])
add_tuning('Tres', 'Standard C major tuning', [['G-4', 'G-3'], ['C-4', 'C-4'],
           ['E-4', 'E-3']])
add_tuning('Ukulele', 'Standard C6 tuning for soprano, concert and tenor.',
           ['G-4', 'C-4', 'E-4', 'A-4'])
add_tuning('Viola', 'Standard tuning. Pitched a 5th below the violin.', ['C-3',
           'G-3', 'D-4', 'A-4'])
add_tuning('Violin', 'Standard tuning', ['G-3', 'D-4', 'A-4', 'E-5'])
add_tuning('Violin', 'Cajun tuning to accompany accordion', ['F-3', 'C-4', 'G-4'
           , 'D-5'])
add_tuning('Walaycho', 'F6 tuning', [['C-4', 'C-4'], ['F-4', 'F-4'], ['A-5',
           'A-4'], ['D-5', 'D-5'], ['A-5', 'A-5']])
add_tuning('Walaycho', 'G6 tuning', [['D-4', 'D-4'], ['G-4', 'G-4'], ['B-5',
           'B-4'], ['E-5', 'E-5'], ['B-5', 'B-5']])
